package com.wll.aop.curd;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @ClassName: CommonDaoAspect.java
 * @author: wanglulu
 * @version: 1.0.0
 * @Description: 一个工具类搞定CRUD的创建人，修改人，时间等字段赋值
 * 本文结合 aop 思想，着重介绍下 Springboot 框架下如何利用切面编程思想实现将创建人、创建时间、更新人、更新时间等基础信息写入数据库。
 * @createTime: 2021/11/24 14:30
 */
@Aspect
@Component
@Configuration
public class CommonDaoAspect {

    /**
     * 创建人
     */
    private static final String creater = "creater";

    /**
     * 创建时间
     */
    private static final String createTime = "createTime";

    /**
     * 修改人
     */
    private static final String updater = "updater";

    /**
     * 修改时间
     */
    private static final String updateTime = "updateTime";

    /**
     * 注：execution(* com.xx.xxxx.*.dao.*.update*(..)) 表示在 dao 目录下的任何文件中的以 update 开头的方法。
     */
    @Pointcut("execution(* com.wll.aop.service.impl.*.update*(..))")
    public void daoUpdate() {
    }

    /**
     * execution(* com.xx.xxxx.*.dao.*.insert*(..)) 表示在 dao 目录下的任何文件中的以 insert 开头的方法。
     */
    @Pointcut("execution(* com.wll.aop.service.impl.*.insert*(..))")
    public void daoCreate() {
    }

    /**
     * 更新
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("daoUpdate()")
    public Object doDaoUpdate(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return pjp.proceed();
        }
//        HttpServletRequest request = attributes.getRequest();
//        String token = request.getHeader("token");
        String username = getUserName();
        if (username != null) {
            Object[] objects = pjp.getArgs();
            if (objects != null && objects.length > 0) {
                for (Object obj : objects) {
                    // 反射 字段属性赋值 方法一
//                    Field field = arg.getClass().getDeclaredField(updateTime);
//                    field.setAccessible(true);
//                    field.set(arg, new Date());

                    // 反射 set方法赋值 方法二
//                    Method method = arg.getClass().getMethod("setUpdateTime", Date.class);
//                    method.setAccessible(true);
//                    method.invoke(arg, new Date());

                    // 方法三 spring的 BeanWrapper
                    BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
                    // 设置修改时间
                    if (beanWrapper.isWritableProperty(updateTime)) {
                        beanWrapper.setPropertyValue(updateTime, new Date());
                    }
                    // 设置修改人
                    if (beanWrapper.isWritableProperty(updater)) {
                        beanWrapper.setPropertyValue(updater, username);
                    }
                }
            }
        }
        Object object = pjp.proceed();
        return object;

    }

    /**
     * 创建
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("daoCreate()")
    public Object doDaoCreate(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return pjp.proceed();
        }
        Object[] objects = pjp.getArgs();
        if (objects != null && objects.length > 0) {
            for (Object obj : objects) {
                String username = getUserName();
                if (username != null) {
                    // 反射 字段属性赋值 方法一
//                    Field field = arg.getClass().getDeclaredField(updateTime);
//                    field.setAccessible(true);
//                    field.set(arg, new Date());

                    // 反射 set方法赋值 方法二
//                    Method method = arg.getClass().getMethod("setUpdateTime", Date.class);
//                    method.setAccessible(true);
//                    method.invoke(arg, new Date());

                    // 方法三 spring的 BeanWrapper
                    BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
                    // 设置创建时间和修改时间
                    if (beanWrapper.isWritableProperty(createTime)) {
                        beanWrapper.setPropertyValue(createTime, new Date());
                    }
                    if (beanWrapper.isWritableProperty(updateTime)) {
                        beanWrapper.setPropertyValue(updateTime, new Date());
                    }
                    // 设置创建人和修改人
                    if (beanWrapper.isWritableProperty(creater)) {
                        beanWrapper.setPropertyValue(creater, username);
                    }
                    if (beanWrapper.isWritableProperty(updater)) {
                        beanWrapper.setPropertyValue(updater, username);
                    }
                }
            }
        }
        Object object = pjp.proceed();
        return object;
    }


    private String getUserName() {
        return "username: lisi";
    }

}
